home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1993…ch: Other People's Memory / ADC Developer CD (1993-03) (''Other People's Memory'')_iso / Dev.CD Mar 93.iso / Technical Documentation / Sample Code / DTS.Lib & Samples / DTS.Chat / Window2.c < prev   
Encoding:
C/C++ Source or Header  |  1992-10-22  |  25.6 KB  |  792 lines  |  [TEXT/MPS ]

  1. /*
  2. ** Apple Macintosh Developer Technical Support
  3. **
  4. ** File:        Window2.c
  5. ** Written by:    Eric Soldan
  6. **
  7. ** Copyright © 1990-1992 Apple Computer, Inc.
  8. ** All rights reserved.
  9. */
  10.  
  11. /* This file contains the code for the document procedure pointers for the main
  12. ** DTS.Chat document.  DTS.Chat only supports two types of documents, types
  13. ** 'DTST' and 'TEXT'.  Type 'TEXT' is only a variant of "DTST', so there isn't
  14. ** a separate code file for it.  Type 'TEXT' doesn't write out header information
  15. ** for the file, as a file of type 'TEXT' is assumed to be all text.  This difference
  16. ** in document type handling is determined in the file File2.c.  The procedure
  17. ** pointers for reading and writing document headers are set to nil, thus turning
  18. ** off that aspect of a document. */
  19.  
  20. /* For more information on this file, please read the read.me file "=How to write your app". */ 
  21.  
  22.  
  23.  
  24. /*****************************************************************************/
  25.  
  26.  
  27.  
  28. #include "App.h"            /* Get the application includes/typedefs, etc.    */
  29. #include "App.Common.h"        /* Get the stuff in common with rez.            */
  30. #include "App.protos.h"        /* Get the prototypes for application.            */
  31.  
  32. #ifndef __CTLHANDLER__
  33. #include "CtlHandler.h"
  34. #endif
  35.  
  36. #ifndef __ERRORS__
  37. #include <Errors.h>
  38. #endif
  39.  
  40. #ifndef __FONTS__
  41. #include <Fonts.h>
  42. #endif
  43.  
  44. #ifndef __LISTCONTROL__
  45. #include "ListControl.h"
  46. #endif
  47.  
  48. #ifndef __RESOURCES__
  49. #include <Resources.h>
  50. #endif
  51.  
  52. #ifndef __TEXTEDITCONTROL__
  53. #include "TextEditControl.h"
  54. #endif
  55.  
  56. #ifndef __TOOLUTILS__
  57. #include <ToolUtils.h>
  58. #endif
  59.  
  60. #ifndef __UTILITIES__
  61. #include "Utilities.h"
  62. #endif
  63.  
  64.  
  65.  
  66. /*****************************************************************************/
  67.  
  68.  
  69.  
  70. #define kMaxNumChars 32000
  71.  
  72. Boolean            gNoDefaultDocument = false;
  73.                     /* Set to true if app should boot with no default document. */
  74.                     /* This tells DTS.Lib..framework what you want. */
  75.  
  76. short            gwAppWindow    = kwAppWindow;    /* Main window attributes. */
  77. short            gMinVersion = kMinVersion;    /* Minimum document version app can support. */
  78. short            gMaxVersion = kMaxVersion;    /* Maximum document version app can support. */
  79.                                             /* More informing DTS.Lib..framework. */
  80.  
  81. extern short        gPrintPage;                /* Non-zero means we are printing. */
  82.                                             /* DTS.Lib..framework global. */
  83.  
  84. extern RgnHandle    gCursorRgn;                /* We handle cursors here, so we need */
  85. extern CursPtr        gCursorPtr;                /* to know about these things. */
  86.                                             /* Above are DTS.Lib..framework globals. */
  87.  
  88. /* Some cursors are pointer-based, and some cursors are resource-based.
  89. ** If a cursor is resource-based, it needs to be loaded and made to not move,
  90. ** and then gCursorPtr can be set to point to it.  This makes all cursors
  91. ** pointer-based.  Also, gCursorPtr is used by DTS.Lib..framework to
  92. ** determine if there is a current cursor.  If gCursorPtr is nil, then
  93. ** there is no current cursor, and the cursor has to be recalculated, no
  94. ** matter where the mouse is.  If gCursorPtr is not nil, then if the
  95. ** mouse position is within the cursor region gCursorRgn, the cursor is
  96. ** correct, and no recalculation is necessary.  If it is outside this region,
  97. ** then it is recalculated.  What does this all mean?  It means that if you
  98. ** want to guarantee that the cursor is recalculated next time DoWindowCursor()
  99. ** is called, set gCursorPtr to nil.
  100. **
  101. ** If you have a cursor resource, you need to:
  102. ** 1) Load the resource.
  103. ** 2) Make a fixed copy of it.
  104. ** 3) Set the cursor to it.
  105. ** 4) Set gCursorPtr to point to the fixed copy.
  106. **
  107. ** There is a function that does almost all of this, called DoSetResCursor().
  108. ** It does all but set gCursorPtr to it.  (It actually sets gCursorPtr to nil.)
  109. ** It does return a pointer to the permanent copy, so typically what you will
  110. ** want to do is the following:
  111. **     gCursorPtr = DoSetResCursor(theCursorID);
  112. **
  113. ** So why set gCursorPtr to nil as the default action?  This allows you to
  114. ** set a temporary cursor, which will be replaced when DoWindowCursor() is
  115. ** called next, or it allows you to set a cursor that maps to the cursor
  116. ** region gCursorRgn (by setting gCursorPtr to the return result). */
  117.  
  118.  
  119.  
  120. /*****************************************************************************/
  121. /*****************************************************************************/
  122.  
  123.  
  124.  
  125. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  126.  
  127. /* Calculate application specific frame area (Called by DoCalcFrameRgn).
  128. ** You are passed an empty region.  You are supposed to add any custom frame
  129. ** parts that this document uses.  Typically there are no frame portions, as
  130. ** they are accounted for in other ways.  The scrollbars and grow icon will
  131. ** automatically be contributed to the calculation of the frame region.
  132. ** If you use sidebars, these are also added in automatically.  This is only
  133. ** used if the frame region is more complicated than can automatically be
  134. ** handled.  So, almost always, you will simply leave the region empty. */
  135.  
  136. #pragma segment TheDoc
  137. void    CalcFrameRgn(FileRecHndl frHndl, WindowPtr window, RgnHandle rgn)
  138. {
  139. #pragma unused (frHndl, window, rgn)
  140. }
  141.  
  142.  
  143.  
  144. /*****************************************************************************/
  145.  
  146.  
  147.  
  148. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  149.  
  150. /* This is called (by DoContentClick()) when a mouse-down event occurs in the content of
  151. ** a window.  Other applications might want to call FindControl, TEClick, etc., to
  152. ** further process the click. */
  153.  
  154. #pragma segment TheDoc
  155. void    ContentClick(WindowPtr window, EventRecord *event, Boolean firstClick)
  156. {
  157. #pragma unused (firstClick)
  158.  
  159.     IsCtlEvent(window, event, nil, nil);
  160.         /* That was easy.  All control-related click actions were just handled. */
  161. }
  162.  
  163.  
  164.  
  165. /*****************************************************************************/
  166.  
  167.  
  168.  
  169. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  170.  
  171. /* DoKeyDown() is first called by the application.  Then if the key isn't a menu
  172. ** key, DoKeyDown() calls this code.  Here are the rules for this function:
  173. **
  174. ** 1) If you handle the key, return(true).  This completes the key handling.
  175. ** 2) If you don't handle the key, you return false.  However, there are two
  176. **    situations for not handling the key:
  177. **      a) You want someone else to.
  178. **      b) You want nobody else to look at the key.
  179. **    This is what the boolean passThrough is for.  If you wish the next window
  180. **    to have a look at the key, set the boolean passThrough to true.  passThrough
  181. **    is already initialized to false, which is the common case, so you only have
  182. **    to worry about setting it true.
  183. **
  184. ** If you have a window that never processes keys and always passes them through,
  185. ** just set the contentKeyProc to nil.  This will indicate to the application
  186. ** framework that all keys should be passed through this window.  DTS.Draw has
  187. ** such a window.  Its palette window doesn't accept keys.  They are passed through
  188. ** to document windows. */
  189.  
  190. #pragma segment TheDoc
  191. Boolean    ContentKey(WindowPtr window, EventRecord *event, Boolean *passThrough)
  192. {
  193. #pragma unused (passThrough)
  194.  
  195.     short    ctlNum, action;
  196.  
  197.     if ((event->message & charCodeMask) == 0x03) {
  198.         SendMessage((FileRecHndl)GetWRefCon(window), kTextMssg);
  199.         return(true);
  200.     }
  201.     ctlNum = IsCtlEvent(window, event, nil, &action);
  202.     if (ctlNum == 2) {
  203.         if (action) {
  204.             SetWindowDirty(window);
  205.             DoAdjustMenus();
  206.             return(true);
  207.         }
  208.     }
  209.  
  210.     return(false);
  211. }
  212.  
  213.  
  214.  
  215. /*****************************************************************************/
  216.  
  217.  
  218.  
  219. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  220.  
  221. /* Draw application specific content (Called by DoDrawFrame).
  222. **
  223. ** If your application has any custom frame areas, or if it uses sidebars,
  224. ** this is the function that you would put the frame drawing code.  The
  225. ** document scrollbars and grow icon drawing is handled by DTS.framework.
  226. ** Just do the sidebar and custom areas here. */
  227.  
  228. #pragma segment TheDoc
  229. void    DrawFrame(FileRecHndl frHndl, WindowPtr window)
  230. {
  231. #pragma unused (frHndl, window)
  232. }
  233.  
  234.  
  235.  
  236. /*****************************************************************************/
  237.  
  238.  
  239.  
  240. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  241.  
  242. /* Frees up any application-specific memory in the document.  This is called by
  243. ** DoFreeDocument, which is called by DisposeDocument().  The application would
  244. ** call DisposeDocument(), not DoFreeDocument() or FreeDocument() directly.
  245. **
  246. ** The document may have a bunch of handles off the main handle of the document.
  247. ** This is where they are freed.  DisposeDocument calls this prior to releasing
  248. ** the ram for the main handle of the document, so release everything else
  249. ** here, or you will have a memory leak.
  250. **
  251. ** NOTE:  Calling DefaultFreeDocument() frees up all memory used by a
  252. ** hierarchical document (see TreeObj package). */
  253.  
  254. #pragma segment TheDoc
  255. OSErr    FreeDocument(FileRecHndl frHndl)
  256. {
  257.     Handle    textHndl;
  258.  
  259.     if (textHndl = (*frHndl)->d.doc.textHndl) {
  260.         DisposHandle(textHndl);
  261.         (*frHndl)->d.doc.textHndl = nil;
  262.     }
  263.     DefaultFreeDocument(frHndl);
  264.  
  265.     return(noErr);
  266. }
  267.  
  268.  
  269.  
  270. /*****************************************************************************/
  271.  
  272.  
  273.  
  274. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  275.  
  276. /* Any additional window disposal tasks can be handled here. */
  277.  
  278. #pragma segment TheDoc
  279. OSErr    FreeWindow(FileRecHndl frHndl, WindowPtr window)
  280. {
  281. #pragma unused (window)
  282.  
  283.     SendMessage(frHndl, kDisconnectMssg);
  284.         /* Let the remote user know the window is closing.  We must handle this,
  285.         ** as DTS.Lib..framework doesn't.   it is application-specific. */
  286.  
  287.     return(noErr);
  288.         /* We always return noErr here, even if SendMessage returned an error.  Why?
  289.         ** Because we don't want the closing of the window to halt just because the
  290.         ** network connection may have been lost, which is about the only error that
  291.         ** can occur.  If there's something bogus about the window, we most likely
  292.         ** want to get rid of it, with good riddance. */
  293. }
  294.  
  295.  
  296.  
  297. /*****************************************************************************/
  298.  
  299.  
  300.  
  301. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  302.  
  303. /* Image the document into the current port.
  304. **
  305. ** The only thing tricky about this function is that it needs to key off of
  306. ** the global variable gPrintPage.  gPrintPage is the current page that is
  307. ** being printed.  If gPrintPage is 0, then you are drawing to the window.
  308. **
  309. ** For when printing:
  310. **
  311. ** If gPrintPage is non-0, that is the page to be printed.  If after imaging
  312. ** the page there are no more pages, you should set gPrintPage to 0.  This
  313. ** indicates to the print loop that the end of the document has been reached.
  314. ** Even if the user indicated in the job dialog to print more pages, setting
  315. ** gPrintPage to 0 states that the last page has been printed.  This is necessary
  316. ** because the print loop can't know when printing is done.  The imaging procedure
  317. ** is the logical one to state when everything has been imaged. */
  318.  
  319. #pragma segment TheDoc
  320. OSErr    ImageDocument(FileRecHndl frHndl)
  321. {
  322.     WindowPtr        thePort;
  323.     Rect            rct, theInk;
  324.     TEHandle        te;
  325.     short            pageCol;
  326.     OSErr            err;
  327.     static short    taskOffset, taskNum;
  328.  
  329.     err = noErr;
  330.     GetPort(&thePort);
  331.  
  332.     if (!gPrintPage) {                                        /* If not printing... */
  333.         DoDrawControls(thePort, false);                        /* Draw the content controls. */
  334.     }
  335.     else {
  336.  
  337.         if (gPrintPage == 1)
  338.             taskOffset = taskNum = 0;
  339.  
  340.         theInk = thePort->portRect;
  341.         InsetRect(&theInk, 4, 4);        /* Just so no characters get clipped. */
  342.  
  343.         pageCol = 0;
  344.         for (rct = theInk; taskNum < 2;) {
  345.             te = (taskNum) ? (*frHndl)->d.doc.outBox : (*frHndl)->d.doc.inBox;
  346.             if (err = CTEPrint(te, &taskOffset, &rct)) break;
  347.             if (taskOffset != -1) return(noErr);    /* Text went to bottom of page. */
  348.             taskOffset = 0;                            /* Done with this TextEdit record. */
  349.             ++taskNum;
  350.             rct.top    = rct.bottom + 20;
  351.             rct.bottom = theInk.bottom;
  352.             if (rct.top + 20 >= rct.bottom) return(noErr);
  353.                 /* No page left or not enough to bother with. */
  354.         }
  355.         gPrintPage = 0;
  356.     }
  357.  
  358.     return(err);
  359. }
  360.  
  361.  
  362.  
  363. /*****************************************************************************/
  364.  
  365.  
  366.  
  367. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  368.  
  369. /* This function does application-specific window content initialization.  In
  370. ** the case of this sample we add the application's controls to a window. */
  371.  
  372. #pragma segment TheDoc
  373. OSErr    InitContent(FileRecHndl frHndl, WindowPtr window)
  374. {
  375.     WindowPtr    oldPort;
  376.     short        i, mode;
  377.     Rect        ctlRect, brdrRect, viewRect, destRect;
  378.     TEHandle    teHndl, textBox[2];
  379.     Handle        text;
  380.     OSErr        err;
  381.  
  382.     err = noErr;
  383.  
  384.     GetPort(&oldPort);
  385.     SetPort(window);
  386.  
  387.     for (i = 0; i < 2; ++i) {
  388.         ctlRect = window->portRect;
  389.         --ctlRect.top;
  390.         --ctlRect.left;
  391.         ctlRect.right  -= 14;
  392.         ctlRect.bottom = ctlRect.top + (ctlRect.bottom - ctlRect.top + 1) / 2;
  393.         if (i) {
  394.             ctlRect.top = ctlRect.bottom - 1;
  395.             ctlRect.bottom = window->portRect.bottom + 1;
  396.         }
  397.         brdrRect = ctlRect;
  398.         viewRect = ctlRect;
  399.         InsetRect(&viewRect, 4, 4);
  400.         destRect = viewRect;
  401.         destRect.right -= 2;    /* This fixes a TextEdit problem where the
  402.                                 ** view has to be a little outside the dest on
  403.                                 ** the right, or else characters are clipped. */
  404.  
  405.         mode = i ? (cteVScrollLessGrow | cteActive) : (cteReadOnly + cteVScroll);
  406.         CTENew(rTECtl,            /* View ctl ResID used for TextEdit control.       */
  407.                window,            /* Window to hold TERecord.                           */
  408.                &teHndl,            /* Return handle for TERecord.                        */
  409.                &ctlRect,        /* Rect for view control.                           */
  410.                &destRect,        /* destRect for TERecord.                           */
  411.                &viewRect,        /* viewRect for TERecord.                           */
  412.                &brdrRect,        /* Used to frame a border.                           */
  413.                kMaxNumChars,    /* Maximum TextEdit document length.               */
  414.                mode                /* Read-only or read-write, vert scroll, grow box. */
  415.         );
  416.         if (!(textBox[i] = teHndl))
  417.             err = memFullErr;
  418.     }
  419.     (*frHndl)->d.doc.inBox  = textBox[0];
  420.     (*frHndl)->d.doc.outBox = textBox[1];
  421.  
  422.     if (text = (*frHndl)->d.doc.textHndl) {
  423.         text = CTESwapText(textBox[1], text, false);
  424.         DisposHandle(text);
  425.         (*frHndl)->d.doc.textHndl = nil;
  426.     }
  427.  
  428.     SetPort(oldPort);
  429.     return(err);
  430. }
  431.  
  432.  
  433.  
  434. /*****************************************************************************/
  435.  
  436.  
  437.  
  438. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  439.  
  440. /* DTS.Chat only kind of uses the hierarchical document package, so it has to
  441. ** do its own file I/O.
  442. **
  443. ** DTS.Chat creates a hierarchical root object, and then never uses it.  This allows
  444. ** DTS.Chat to serve as an expandable sample application if you wish to start using it
  445. ** as such.  Most likely though, you would want to start with Zippo, as it is nearly
  446. ** the same as DTS.Chat, but with the "chat" stuff removed. */
  447.  
  448. #pragma segment TheDoc
  449. OSErr    ReadDocument(FileRecHndl frHndl)
  450. {
  451.     short    fileRefNum;
  452.     OSErr    err;
  453.     char    hstate;
  454.     long    count;
  455.     Handle    textHndl;
  456.  
  457.     fileRefNum = (*frHndl)->fileState.refNum;
  458.  
  459.     err = SetFPos(fileRefNum, fsFromStart, 0);
  460.         /* Set the file position to the beginning of the file. */
  461.  
  462.     if (!err)
  463.         err = DoReadDocumentHeader(frHndl);
  464.             /* Read the document header.
  465.             ** Note that this doesn't guarantee that we will actually do something.
  466.             ** Text documents don't have a header.  The read and write header procs have
  467.             ** been set to nil for text documents, so calling DoReadDocumentHeader
  468.             ** will do nothing for text documents.  DTS.Chat documents do have a header,
  469.             ** and by calling DoReadDocumentHeader, the header will be read in. */
  470.  
  471.     if (!err) {        /* Read TextEdit text from file. */
  472.         textHndl = NewHandle(kMaxNumChars);
  473.         if (!(err = MemError())) {
  474.             count = kMaxNumChars;
  475.                 /* The size of the text isn't saved to disk.  This is the maximum
  476.                 ** that a TextEdit record can accept. */
  477.             hstate = LockHandleHigh(textHndl);
  478.             err    = FSRead(fileRefNum, &count, *textHndl);
  479.             HSetState(textHndl, hstate);
  480.  
  481.             if (err == eofErr)
  482.                 err = noErr;
  483.  
  484.             if (err)
  485.                 count = 0;
  486.  
  487.             SetHandleSize(textHndl, count);
  488.                 /* Set the handle to the actual size of the text on disk. */
  489.             (*frHndl)->d.doc.textHndl = textHndl;
  490.         }
  491.     }
  492.  
  493.     return(err);
  494. }
  495.  
  496.  
  497.  
  498. /*****************************************************************************/
  499.  
  500.  
  501.  
  502. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  503.  
  504. /* Resize application specific content  (Called by ResizeWindow). */
  505.  
  506. #pragma segment TheDoc
  507. void    ResizeContent(WindowPtr window, short oldh, short oldv)
  508. {
  509. #pragma unused (oldh, oldv)
  510.  
  511.     FileRecHndl    frHndl;
  512.     WindowPtr    oldPort;
  513.     short        i;
  514.     Rect        rct;
  515.     TEHandle    te;
  516.  
  517.     if (!window) return;
  518.  
  519.     frHndl  = (FileRecHndl)GetWRefCon(window);
  520.     oldPort = SetFilePort(frHndl);
  521.  
  522.     for (i = 0; i < 2; ++i) {
  523.         rct = window->portRect;
  524.         --rct.top;
  525.         --rct.left;
  526.         rct.right  -= 14;
  527.         rct.bottom = rct.top + (rct.bottom - rct.top + 1) / 2;
  528.         if (i) {
  529.             rct.top = rct.bottom - 1;
  530.             rct.bottom = window->portRect.bottom + 1;
  531.         }
  532.  
  533.         te = (i) ? (*frHndl)->d.doc.outBox : (*frHndl)->d.doc.inBox;
  534.         CTEMove(te, rct.left, rct.top);
  535.         CTESize(te, rct.right - rct.left, rct.bottom - rct.top, true);
  536.     }
  537.  
  538.     SetPort(oldPort);
  539. }
  540.  
  541.  
  542.  
  543. /*****************************************************************************/
  544.  
  545.  
  546.  
  547. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  548.  
  549. /* Scroll application specific frame (Called by DoScrollFrame).
  550. **
  551. ** Some applications may need to scroll the "frame" of the document along
  552. ** with the document contents.  This is common for applications with rulers,
  553. ** or other similar sidebar items. */
  554.  
  555. #pragma segment TheDoc
  556. void    ScrollFrame(FileRecHndl frHndl, WindowPtr window, long dh, long dv)
  557. {
  558. #pragma unused (frHndl, window, dh, dv)
  559. }
  560.  
  561.  
  562.  
  563. /*****************************************************************************/
  564.  
  565.  
  566.  
  567. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  568.  
  569. /* Since the hierarchical document package isn't used by DTS.Chat,
  570. ** this function actually never gets called. */
  571.  
  572. #pragma segment TheDoc
  573. void    UndoFixup(FileRecHndl frHndl, Point contOrg, Boolean afterUndo)
  574. {
  575. #pragma unused (frHndl, contOrg, afterUndo)
  576. }
  577.  
  578.  
  579.  
  580. /*****************************************************************************/
  581.  
  582.  
  583.  
  584. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  585.  
  586. /* This function is where you adjust the cursor to reflect the location in the
  587. ** document or window.  You have the additional input of gCursorRgn to deal
  588. ** with.  The way that the cursor handling works is as follows:
  589. ** 1) The application calls DoWindowCursor().
  590. ** 2) DoWindowCursor() works its way through the windows/documents, front to back.
  591. **    It looks at the document's windowCursorProc and checks to see if the document
  592. **    has one.  If the document doesn't have one, then it assumes that that window
  593. **    always wants an arrow.  If the cursor is over that window, the cursor is set
  594. **    to an arrow, and we're done.  If the cursor isn't over the window, then the next
  595. **    window is tried.  If all documents don't have a windowCursorProc, then the cursor
  596. **    is set to an arrow (for the non-document area of the screen).
  597. ** 3) If a document has a windowCursorProc, then the proc is called.  The proc's
  598. **    job is as follows:
  599. **    a) If the cursor is over a position that is determined by the window, then
  600. **       the proc removes other areas from gCursorRgn.  Note that it should not
  601. **       simply set the area to what it "thinks" is the correct area.  This window
  602. **       may not be the front-most.  Other windows will have already been subtracted
  603. **       from gCursorRgn.  The resultant gCursorRgn is the correct cursor area,
  604. **       and should be passed to WaitNextEvent calls in the application (already the case
  605. **       in EventLoop.c).  Also, the cursor should be set to the correct cursor, of course.
  606. **       You should also return true, as the cursor has been determined.
  607. **    b) If the cursor is not over a position for this window, then you should
  608. **       return.  You will either pass back true or false.  If you don't wish
  609. **       windows behind this window to have a shot at cursor determination, then
  610. **       return true.  This states that the cursor is "determined".  It is, in the
  611. **       sense that no further determination will occur.  If you return false, then
  612. **       other windows get a shot at determining the cursor.
  613. **
  614. ** Setting the cursor to the correct cursor isn't as easy as you would expect.
  615. ** DTS.Lib..framework uses the global gCursorPtr as the reference to the cursor.  This is
  616. ** fine if the cursor is pointer-based, but if the cursor is resource-based, it is a bit
  617. ** more of a problem.  What you will need to do is to call DoSetResCursor() to make the
  618. ** resource cursor pointer-based.  DoSetResCursor() will set gCursorPtr to nil, and it
  619. ** also returns the pointer to the permanent copy of the cursor resource.  Just set gCursorPtr
  620. ** to the return result of DoSetResCursor(), and you will be set. */
  621.  
  622. #pragma segment TheDoc
  623. Boolean    WindowCursor(FileRecHndl frHndl, WindowPtr window, Point globalPt)
  624. {
  625.     WindowPtr        oldPort;
  626.     RgnHandle        contRgn;
  627.     Rect            outBoxRct, teViewRct, contRct;
  628.     TEHandle        outBox, teHndl;
  629.     ControlHandle    viewCtl;
  630.     Point            contOrg;
  631.  
  632.     /* For the DTS.Chat sample, we display an i-beam cursor when over the outbox. */
  633.  
  634.     CopyRgn(((WindowPeek)window)->contRgn, (contRgn = NewRgn()));
  635.     viewCtl   = CTEViewFromTE(outBox = (*frHndl)->d.doc.outBox);
  636.     outBoxRct = (*viewCtl)->contrlRect;        /* Local coordinates of outbox. */
  637.     InsetRect(&outBoxRct, 2, 2);
  638.     GetContentOrigin(window, &contOrg);        /* Scroll position of window. */
  639.     OffsetRect(&outBoxRct, -contOrg.h, -contOrg.v);
  640.         /* By offseting the outbox rect by the amount scrolled, we now have
  641.         ** the local position of the outbox within the potentially scrolled
  642.         ** window content. */
  643.     GetContentRect(window, &contRct);
  644.         /* This returns the content portion of the window in local coordinates,
  645.         ** less document scrollbar area. */
  646.     SectRect(&outBoxRct, &contRct, &outBoxRct);
  647.         /* Part of the outbox still visible after scrolling. */
  648.  
  649.     GetPort(&oldPort);
  650.     SetPort(window);
  651.     LocalToGlobalRect(&outBoxRct);
  652.     SetPort(oldPort);
  653.         /* The outbox rect, in global coordinates. */
  654.  
  655.     if (CTETargetInfo(&teHndl, &teViewRct) == window) {
  656.         /* If target TextEdit control belongs to this window... */
  657.  
  658.         if ((teHndl == outBox) && (PtInRect(globalPt, &outBoxRct))) {
  659.             /* If target TextEdit control is the outbox, and the cursor
  660.             ** is over the visible part of the outbox... */
  661.  
  662.             gCursorPtr = DoSetResCursor(ibeamCursor);
  663.             RectRgn(contRgn, &outBoxRct);
  664.             SectRgn(gCursorRgn, contRgn, gCursorRgn);
  665.             DisposeRgn(contRgn);
  666.             return(true);
  667.         }
  668.     }
  669.  
  670.     DiffRgn(((WindowPeek)window)->strucRgn, contRgn, contRgn);
  671.     SectRgn(gCursorRgn, contRgn, gCursorRgn);
  672.     DisposeRgn(contRgn);
  673.     SetCursor(gCursorPtr = &qd.arrow);
  674.     return(true);
  675. }
  676.  
  677.  
  678.  
  679. /*****************************************************************************/
  680.  
  681.  
  682.  
  683. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  684.  
  685. /* After the DTS.Lib framework disposes of a window, it calls here.  This is
  686. ** to give the application a chance to do any additional tasks related to
  687. ** a window closing.  DTS.Chat doesn't have anything else extra to do. */
  688.  
  689. #pragma segment TheDoc
  690. void    WindowGoneFixup(WindowPtr window)
  691. {
  692. #pragma unused (window)
  693. }
  694.  
  695.  
  696.  
  697. /*****************************************************************************/
  698.  
  699.  
  700.  
  701. /* •• You don't call this.  DTS.Lib..framework does for appropriate document type(s). •• */
  702.  
  703. /* DTS.Chat only kind of uses the hierarchical document package, so it has to
  704. ** do its own file I/O.
  705. **
  706. ** DTS.Chat creates a hierarchical root object, and then never uses it.  This allows
  707. ** DTS.Chat to serve as an expandable sample application if you wish to start using it
  708. ** as such.  Most likely though, you would want to start with Zippo, as it is nearly
  709. ** the same as DTS.Chat, but with the "chat" stuff removed. */
  710.  
  711. #pragma segment TheDoc
  712. OSErr    WriteDocument(FileRecHndl frHndl)
  713. {
  714.     short        fileRefNum;
  715.     OSErr        err;
  716.     char        hstate;
  717.     long        count, fpos;
  718.     TEHandle    te;
  719.     Handle        textHndl;
  720.  
  721.     fileRefNum = (*frHndl)->fileState.refNum;
  722.  
  723.     err = SetFPos(fileRefNum, fsFromStart, 0);
  724.         /* Set the file position to the beginning of the file. */
  725.  
  726.     if (!err)
  727.         err = DoWriteDocumentHeader(frHndl);
  728.             /* Write the document header.
  729.             ** Note that this doesn't guarantee that we will actually do something.
  730.             ** Text documents don't have a header.  The read and write header procs have
  731.             ** been set to nil for text documents, so calling DoWriteDocumentHeader
  732.             ** will do nothing for text documents.  DTS.Chat documents do have a header,
  733.             ** and by calling DoWriteDocumentHeader, the header will be written out. */
  734.  
  735.     if (!err) {        /* Write out-box TextEdit control text to file. */
  736.         te       = (*frHndl)->d.doc.outBox;
  737.         textHndl = (*te)->hText;
  738.         count    = (*te)->teLength;
  739.         hstate   = LockHandleHigh(textHndl);
  740.         err      = FSWrite(fileRefNum, &count, *textHndl);
  741.         HSetState(textHndl, hstate);
  742.     }
  743.  
  744.     if (!err) {
  745.         err = GetFPos(fileRefNum, &fpos);
  746.         if (!err)
  747.             err = SetEOF(fileRefNum, fpos);
  748.     }            /* The document may be shorter than last time it was written to disk.
  749.                 ** Handle this case by ending the file based on the new length. */
  750.  
  751.     return(err);
  752. }
  753.  
  754.  
  755.  
  756. /*****************************************************************************/
  757. /*****************************************************************************/
  758.  
  759.  
  760.  
  761. #pragma segment TheDoc
  762. OSErr    DuplicateDocument(FileRecHndl oldFrHndl, FileRecHndl *newFrHndl)
  763. {
  764.     OSErr        err;
  765.     TEHandle    te;
  766.     Handle        oldHndl, newHndl;
  767.     long        size;
  768.  
  769.     err = NewDocument(newFrHndl, (*oldFrHndl)->fileState.sfType, true);
  770.         /* Create a document and root object to copy the file data into. */
  771.  
  772.     if (err) return(err);
  773.  
  774.     te      = (*oldFrHndl)->d.doc.outBox;
  775.     oldHndl = (*te)->hText;
  776.     size    = (*te)->teLength;
  777.     if (newHndl = NewHandle(size)) {
  778.         (**newFrHndl)->d.doc.textHndl = newHndl;
  779.         BlockMove(*oldHndl, *newHndl, size);
  780.     }
  781.     else {
  782.         err = MemError();
  783.         DisposeDocument(*newFrHndl);
  784.         *newFrHndl = nil;
  785.     }
  786.  
  787.     return(err);
  788. }
  789.  
  790.  
  791.  
  792.